home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / xinetd / xinetd.2.0.6 / service.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-22  |  14.7 KB  |  674 lines

  1. /*
  2.  * (c) Copyright 1992 by Panagiotis Tsirigotis
  3.  * All rights reserved.  The file named COPYRIGHT specifies the terms 
  4.  * and conditions for redistribution.
  5.  */
  6.  
  7. static char RCSid[] = "$Id: service.c,v 5.2 1992/11/10 08:18:25 panos Exp $" ;
  8.  
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #include <netdb.h>
  13. #include <syslog.h>
  14. #include <fcntl.h>
  15.  
  16. #include "fsma.h"
  17. #include "sio.h"
  18.  
  19. #include "options.h"
  20.  
  21. #include "access.h"
  22. #include "attr.h"
  23. #include "service.h"
  24. #include "server.h"
  25. #include "state.h"
  26. #include "config.h"
  27. #include "connection.h"
  28. #include "logoptions.h"
  29.  
  30. #define SUSPEND( sp )            (sp)->state = SVC_SUSPENDED
  31. #define RESUME( sp )                (sp)->state = SVC_ACTIVE
  32. #define DISABLE( sp )            (sp)->state = SVC_DISABLED
  33.  
  34.  
  35. void msg() ;
  36. void out_of_memory() ;
  37.  
  38. time_t time() ;
  39.  
  40. static fsma_h service_allocator ;
  41.  
  42. static struct name_value service_states[] =
  43.    {
  44.       { "Not started",        (int) SVC_NOT_STARTED   },
  45.       { "Active",             (int) SVC_ACTIVE        },
  46.       { "Disabled",           (int) SVC_DISABLED      },
  47.       { NULL,                 0                       }
  48.    } ;
  49.  
  50.  
  51.  
  52. status_e svc_init()
  53. {
  54.     int flags = FSM_RETURN_ERROR + FSM_ZERO_ALLOC ;
  55.  
  56. #ifdef DEBUG
  57.     flags |= FSM_ZERO_FREE ;
  58. #endif
  59.     service_allocator = fsm_create( sizeof( struct service ), 0, flags ) ;
  60.     return( ( service_allocator == NULL ) ? FAILED : OK ) ;
  61. }
  62.  
  63.  
  64. /*
  65.  * Allocate a new struct service and initialize it from scp 
  66.  */
  67. struct service *svc_new( scp )
  68.     struct service_config *scp ;
  69. {
  70.     struct service *sp ;
  71.     char *func = "svc_new" ;
  72.  
  73.     sp = SP( fsm_alloc( service_allocator ) ) ;
  74.    if ( sp == NULL )
  75.    {
  76.       out_of_memory( func ) ;
  77.       return( NULL ) ;
  78.    }
  79.  
  80.     if ( scp != NULL )
  81.         *CONF( sp ) = *scp ;
  82.     return( sp ) ;
  83. }
  84.  
  85.  
  86. /*
  87.  * Allocate a new struct service, initialize it from scp and 
  88.  * insert it in stab
  89.  */
  90. struct service *svc_alloc( scp, stab )
  91.     struct service_config *scp ;
  92.     pset_h stab ;
  93. {
  94.     struct service *sp ;
  95.     char *func = "svc_alloc" ;
  96.  
  97.     if ( ( sp = svc_new( scp ) ) == NULL )
  98.         return( NULL ) ;
  99.  
  100.    if ( pset_add( stab, sp ) == NULL )
  101.    {
  102.       out_of_memory( func ) ;
  103.       fsm_free( service_allocator, (char *) sp ) ;
  104.       return( NULL ) ;
  105.    }
  106.     return( sp ) ;
  107. }
  108.  
  109.  
  110. /*
  111.  * NOTE:    We assume that the service_allocator has been initialized
  112.  */
  113. void svc_free( sp )
  114.    struct service *sp ;
  115. {
  116.    sconf_free( CONF( sp ) ) ;
  117.    fsm_free( service_allocator, (char *) sp ) ;
  118. }
  119.  
  120.  
  121. void svc_setup_address_control( sp )
  122.     struct service *sp ;
  123. {
  124.     register struct service_data *sdp = SDATA( sp ) ;
  125.     register struct service_config *scp = CONF( sp ) ;
  126.  
  127.     if ( IS_PRESENT( scp, A_ONLY_FROM ) )
  128.         sdp->only_from = scp->only_from ;
  129.     else if ( SPECIFIED( DEFAULTS( ps ), A_ONLY_FROM ) )
  130.         sdp->only_from = DEFAULTS( ps )->only_from ;
  131.     else
  132.         sdp->only_from = NULL ;
  133.     if ( IS_PRESENT( scp, A_NO_ACCESS ) )
  134.         sdp->no_access = scp->no_access ;
  135.     else if ( SPECIFIED( DEFAULTS( ps ), A_NO_ACCESS ) )
  136.         sdp->no_access = DEFAULTS( ps )->no_access ;
  137.     else
  138.         sdp->no_access = NULL ;
  139. }
  140.  
  141.  
  142. PRIVATE status_e set_fd_modes( sp )
  143.     struct service *sp ;
  144. {
  145.     struct service_config *scp = CONF( sp ) ;
  146.     int sd = SVC_FD( sp ) ;
  147.     char *func = "set_fd_modes" ;
  148.  
  149.    /*
  150.     * There is a possibility of blocking on a send/write if
  151.     *
  152.     *    the service is internal    AND
  153.     *    it does not require forking another process AND
  154.     *    it does not accept connections
  155.     *
  156.     * To avoid this, we put the descriptor in FNDELAY mode.
  157.     * (if the service accepts connections, we still need to put the
  158.     * 'accepted' connection in FNDELAY mode but this is done in start_server)
  159.     */
  160.     if ( IS_INTERNAL( scp ) &&
  161.            sp->builtin->fork_server == NO &&
  162.                         ! ACCEPTS_CONNECTIONS( scp ) &&
  163.                               fcntl( sd, F_SETFL, FNDELAY ) == -1 )
  164.    {
  165.       msg( LOG_ERR, func,
  166.          "fcntl failed (%m) for FNDELAY. service = %s", scp->id ) ;
  167.         return( FAILED ) ;
  168.    }
  169.  
  170.    /*
  171.     * Always set the close-on-exec flag
  172.     */
  173.    if ( fcntl( sd, F_SETFD, 1 ) == -1 )
  174.    {
  175.       msg( LOG_ERR, func,
  176.          "fcntl failed (%m) for close-on-exec. service = %s", scp->id ) ;
  177.       return( FAILED ) ;
  178.    }
  179.     return( OK ) ;
  180. }
  181.  
  182.  
  183. #ifndef NO_RPC
  184.  
  185. PRIVATE status_e activate_rpc( sp )
  186.    register struct service *sp ;
  187. {
  188.     struct sockaddr_in sin ;
  189.     int sin_len ;
  190.     struct service_config *scp = CONF( sp ) ;
  191.     struct rpc_data *rdp = RPCDATA( scp ) ;
  192.     unsigned long vers ;
  193.     unsigned registered_versions = 0 ;
  194.     int sd = SVC_FD( sp ) ;
  195.     char *func = "activate_rpc" ;
  196.  
  197.     CLEAR( sin ) ;
  198.  
  199.     sin.sin_family = AF_INET ;
  200.     sin.sin_addr.s_addr = htonl( INADDR_ANY ) ;
  201.     sin.sin_port = 0 ;         /* let the system give us a port */
  202.     if ( bind( sd, SA( &sin ), sizeof( sin ) ) == -1 )
  203.     {
  204.         msg( LOG_ERR, func, "bind failed (%m). service = %s", scp->id ) ;
  205.         return( FAILED ) ;
  206.     }
  207.  
  208.     /*
  209.      * Find the port number that was assigned to the socket
  210.      */
  211.     sin_len = sizeof( sin ) ;
  212.     if ( getsockname( sd, SA( &sin ), &sin_len ) == -1 )
  213.     {
  214.         msg( LOG_ERR, func, "getsockname failed (%m). service = %s", scp->id ) ;
  215.         return( FAILED ) ;
  216.     }
  217.     scp->port = ntohs( sin.sin_port ) ;
  218.  
  219.     /*
  220.      * Try to register as many versions as possible
  221.      */
  222.     for ( vers = rdp->min_version ; vers <= rdp->max_version ; vers++ )
  223.         if ( pmap_set( rdp->program_number, vers,
  224.                                         scp->protocol.value, scp->port ) )
  225.             registered_versions++ ;
  226.         else
  227.             msg( LOG_ERR, func,
  228.                 "pmap_set failed. service=%s program=%ld version=%ld",
  229.                     scp->id, rdp->program_number, vers ) ;
  230.  
  231.     if ( debug.on )
  232.         msg( LOG_DEBUG, func,
  233.                     "Registered %d versions of %s", registered_versions, scp->id ) ;
  234.  
  235.     return( ( registered_versions == 0 ) ? FAILED : OK ) ;
  236. }
  237.  
  238. #endif    /* ! NO_RPC */
  239.  
  240.  
  241. PRIVATE status_e activate_normal( sp )
  242.    register struct service *sp ;
  243. {
  244.     struct sockaddr_in sin ;
  245.     int sd = SVC_FD( sp ) ;
  246.     struct service_config *scp = CONF( sp ) ;
  247.     char *func = "activate_normal" ;
  248.  
  249.     CLEAR( sin ) ;
  250.  
  251.     sin.sin_family = AF_INET ;
  252.     sin.sin_addr.s_addr = htonl( INADDR_ANY ) ;
  253.     sin.sin_port = htons( scp->port ) ;
  254.  
  255.     if ( reuse_option || M_IS_SET( scp->flags, SF_REUSE ) )
  256.     {
  257.         int on = 1 ;
  258.  
  259.         if ( setsockopt( sd, SOL_SOCKET,
  260.                         SO_REUSEADDR, (char *) &on, sizeof( on ) ) == -1 )
  261.             msg( LOG_WARNING, func,
  262.                 "setsockopt SO_REUSEADDR failed (%m). service = %s", scp->id ) ;
  263.     }
  264.  
  265.     if ( bind( sd, SA( &sin ), sizeof( sin ) ) == -1 )
  266.     {
  267.         msg( LOG_ERR, func, "bind failed (%m). service = %s", scp->id ) ;
  268.         return( FAILED ) ;
  269.     }
  270.     return( OK ) ;
  271. }
  272.  
  273.  
  274. /*
  275.  * Activate a service. 
  276.  */
  277. status_e svc_activate( sp )
  278.    register struct service *sp ;
  279. {
  280.     struct service_config *scp = CONF( sp ) ;
  281.     struct service_data *sdp = SDATA( sp ) ;
  282.     status_e status ;
  283.    char *func = "activate_service" ;
  284.     voidfunc get_shutdown_by_name() ;
  285.     status_e start_log() ;
  286.     status_e svc_generic_handler() ;
  287.     void deactivate() ;
  288.  
  289.     sdp->service_fd = socket( AF_INET, scp->socket_type, scp->protocol.value ) ;
  290.  
  291.    if ( sdp->service_fd == -1 )
  292.    {
  293.       msg( LOG_ERR, func,
  294.                         "socket creation failed (%m). service = %s", scp->id ) ;
  295.         return( FAILED ) ;
  296.    }
  297.  
  298.     if ( set_fd_modes( sp ) == FAILED )
  299.     {
  300.         (void) close( sdp->service_fd ) ;
  301.         return( FAILED ) ;
  302.     }
  303.  
  304. #ifndef NO_RPC
  305.    if ( IS_RPC( scp ) )
  306.         status = activate_rpc( sp ) ;
  307.    else
  308. #endif   /* ! NO_RPC */
  309.         status = activate_normal( sp ) ;
  310.     
  311.     if ( status == FAILED )
  312.     {
  313.         (void) close( sdp->service_fd ) ;
  314.         return( FAILED ) ;
  315.     }
  316.  
  317.     if ( start_log( sp ) == FAILED )
  318.     {
  319.         deactivate( sp ) ;
  320.         return( FAILED ) ;
  321.     }
  322.  
  323.     /*
  324.      * Initialize the service data
  325.      */
  326.     sdp->running_servers = sdp->retry_servers = 0 ;
  327.     sdp->postmortem = server_postmortem ;
  328.     sdp->shutdown = get_shutdown_by_name( scp->name ) ;
  329.     sdp->handler = svc_generic_handler ;
  330.     svc_setup_address_control( sp ) ;
  331.  
  332.    if ( MUST_LISTEN( scp ) )
  333.       (void) listen( sdp->service_fd, LISTEN_BACKLOG ) ;
  334.  
  335.    ps.rws.descriptors_free-- ;
  336.  
  337.     sp->state = SVC_ACTIVE ;
  338.  
  339.     FD_SET( sdp->service_fd, &ps.rws.socket_mask ) ;
  340.     if ( sdp->service_fd > ps.rws.mask_max )
  341.         ps.rws.mask_max = sdp->service_fd ;
  342.  
  343.     ps.rws.active_services++ ;
  344.     ps.rws.available_services++ ;
  345.  
  346.    return( OK ) ;
  347. }
  348.  
  349.  
  350. PRIVATE void deactivate( sp )
  351.     register struct service *sp ;
  352. {
  353.     (void) close( SVC_FD( sp ) ) ;
  354.  
  355. #ifndef NO_RPC
  356.     if ( IS_RPC( CONF( sp ) ) )
  357.     {
  358.         register unsigned long vers ;
  359.         register struct rpc_data *rdp = RPCDATA( CONF( sp ) ) ;
  360.  
  361.         for ( vers = rdp->min_version ; vers <= rdp->max_version ; vers++ )
  362.             (void) pmap_unset( rdp->program_number, vers ) ;
  363.     }
  364. #endif    /* ! NO_RPC */
  365. }
  366.  
  367.  
  368. /*
  369.  * Close the service descriptor.
  370.  * If an RPC service, deregister it.
  371.  * Close the log.
  372.  */
  373. void svc_deactivate( sp )
  374.    register struct service *sp ;
  375. {
  376.     void end_log() ;
  377.  
  378.     if ( ! IS_AVAILABLE( sp ) )
  379.         return ;
  380.  
  381.     deactivate( sp ) ;
  382.    ps.rws.descriptors_free++ ;
  383.  
  384.     if ( SDATA( sp )->log_handle )
  385.         end_log( LOG( CONF( sp ) )->log_type, SDATA( sp )->log_handle ) ;
  386.  
  387.     if ( IS_ACTIVE( sp ) )
  388.     {
  389.         FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ;
  390.         ps.rws.active_services-- ;
  391.     }
  392.  
  393.     ps.rws.available_services-- ;
  394.  
  395.     DISABLE( sp ) ;
  396. }
  397.  
  398.  
  399.  
  400. /*
  401.  * Suspend a service
  402.  */
  403. void svc_suspend( sp )
  404.     struct service *sp ;
  405. {
  406.     char *func = "suspend_service" ;
  407.  
  408.     if ( ! IS_ACTIVE( sp ) )
  409.     {
  410.         msg( LOG_ERR, func, "service %s is not active", CONF( sp )->id ) ;
  411.         return ;
  412.     }
  413.  
  414.     FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ;
  415.     ps.rws.active_services-- ;
  416.     if ( debug.on )
  417.         msg( LOG_DEBUG, func, "Suspended service %s", CONF( sp )->id ) ;
  418.     
  419.     SUSPEND( sp ) ;
  420. }
  421.  
  422.  
  423. /*
  424.  * Resume a suspended service.
  425.  */
  426. void svc_resume( sp )
  427.     struct service *sp ;
  428. {
  429.     char *func = "resume_service" ;
  430.  
  431.     if ( IS_SUSPENDED( sp ) )
  432.     {
  433.         FD_SET( SVC_FD( sp ), &ps.rws.socket_mask ) ;
  434.         ps.rws.active_services++ ;
  435.         if ( debug.on )
  436.             msg( LOG_DEBUG, func, "Resumed service %s", CONF( sp )->id ) ;
  437.         RESUME( sp ) ;
  438.     }
  439. }
  440.  
  441.  
  442. /*
  443.  * Steps:
  444.  *        1. Deactivate the service
  445.  *        2. Free all memory used by the service and free the service itself
  446.  *
  447.  * Since this function may free all memory associated with the service as
  448.  * well as the memory pointed by sp, only the value of sp should be used
  449.  * after this call (i.e. no dereferencing of sp).
  450.  */
  451. int svc_release( sp )
  452.    struct service *sp ;
  453. {
  454.     char *func = "svc_release" ;
  455.     char *sid = CONF( sp )->id ;
  456.  
  457.     if ( sp->ref_count == 0 )
  458.     {
  459.         msg( LOG_ERR, func, "%s: svc_release with 0 count", sid ) ;
  460.         return( 0 ) ;
  461.     }
  462.     
  463.     sp->ref_count-- ;
  464.     if ( sp->ref_count == 0 )
  465.     {
  466.         if ( debug.on )
  467.             msg( LOG_DEBUG, func, "ref count of service %s dropped to 0", sid ) ;
  468.         svc_deactivate( sp ) ;
  469.         svc_free( sp ) ;
  470.         return( 0 ) ;
  471.     }
  472.     else
  473.         return( sp->ref_count ) ;
  474. }
  475.  
  476.  
  477.  
  478. void svc_dump( sp, fd )
  479.     struct service *sp ;
  480.     int fd ;
  481. {
  482.     register struct service_data *sdp = SDATA( sp ) ;
  483.     struct name_value *nvp ;
  484.     void sconf_dump() ;
  485.     char *get_shutdown_by_addr() ;
  486.     void tabprint() ;
  487.  
  488.     tabprint( fd, 0, "Service = %s\n", CONF( sp )->name ) ;
  489.     tabprint( fd, 1, "State = %s\n",
  490.         ( nvp = nv_find_name( service_states, (int) sp->state ) )
  491.                 ? nvp->name : "BAD STATE" ) ;
  492.  
  493.     sconf_dump( CONF( sp ), fd, 1, FALSE ) ;
  494.  
  495.     if ( sp->state == SVC_ACTIVE )
  496.     {
  497.         tabprint( fd, 1, "Service data\n" ) ;
  498.         tabprint( fd, 2, "running servers = %d\n", sdp->running_servers ) ;
  499.         tabprint( fd, 2, "retry servers = %d\n", sdp->retry_servers ) ;
  500.         tabprint( fd, 2, "attempts = %d\n", sdp->attempts ) ;
  501.         tabprint( fd, 2, "service fd = %d\n", sdp->service_fd ) ;
  502.         tabprint( fd, 2, "post mortem function = %p\n", sdp->postmortem ) ;
  503.         tabprint( fd, 2, "shutdown function = %s\n",
  504.                             get_shutdown_by_addr( sdp->shutdown ) ) ;
  505.     }
  506.     Sputchar( fd, '\n' ) ;
  507. }
  508.  
  509.  
  510. /*
  511.  * Returns TRUE if the server instantiation rate is over the limit
  512.  */
  513. bool_int svc_looping( sp )
  514.     struct service *sp ;
  515. {
  516.     register struct service_data *sdp = SDATA( sp ) ;
  517.     time_t current_time ;
  518.     time_t time_diff ;
  519.     char *func = "loop_check" ;
  520.  
  521.     (void) time( ¤t_time ) ;
  522.  
  523.     if ( sdp->attempts == 0 )
  524.     {
  525.         sdp->attempts++ ;
  526.         sdp->start_time = current_time ;
  527.         return( FALSE ) ;
  528.     }
  529.  
  530.     time_diff = current_time - sdp->start_time ;
  531.     if ( time_diff <= LOOP_INTERVAL )
  532.     {
  533.         sdp->attempts++ ;
  534.         if ( time_diff == 0 )
  535.             time_diff = 1 ;
  536.         if ( sdp->attempts/time_diff > ps.ros.loop_rate )
  537.         {
  538.             FD_CLR( SVC_FD( sp ), &ps.rws.socket_mask ) ;
  539.             svc_deactivate( sp ) ;
  540.             msg( LOG_ERR, func,
  541.                 "%s service was deactivated because of looping", CONF( sp )->id ) ;
  542.             return( TRUE ) ;
  543.         }
  544.     }
  545.     else
  546.     {
  547.         sdp->start_time = current_time ;
  548.         sdp->attempts = 1 ;
  549.     }
  550.     return( FALSE ) ;
  551. }
  552.  
  553.  
  554.  
  555. void svc_request( sp )
  556.     struct service *sp ;
  557. {
  558.     connection_s *cp ;
  559.  
  560.     cp = conn_new( sp ) ;
  561.     if ( cp == NULL )
  562.         return ;
  563.  
  564.     if ( SVC_HANDLE( sp, cp ) == OK )
  565.     {
  566.         if ( SVC_FORKS( sp ) )
  567.         {
  568.             conn_close( cp ) ;
  569.             if ( CONF( sp )->wait == YES )
  570.                 svc_suspend( sp ) ;
  571.         }
  572.         else
  573.             conn_free( cp ) ;
  574.     }
  575.     else
  576.     {
  577.         conn_cleanup( cp ) ;
  578.         if ( conn_start_alternative( cp ) == FAILED )
  579.             conn_free( cp ) ;
  580.     }
  581. }
  582.  
  583.  
  584.  
  585. PRIVATE status_e svc_generic_handler( sp, cp )
  586.     struct service *sp ;
  587.     connection_s *cp ;
  588. {
  589.     struct service_config *scp = CONF( sp ) ;
  590.  
  591.    /*
  592.     * There is no loop check for services that accept connections because
  593.     * the connections are accepted by xinetd, therefore the queue will get
  594.     * empty eventually even if the server is faulty.
  595.     * Services for which no fork(2) occurs are not checked because
  596.     *    a) they are internal and we assume they are not faulty
  597.     *    b) we have no way of determining if something is going wrong
  598.     *       for example, UDP discard can do its job very quickly
  599.     */
  600.     if ( !ACCEPTS_CONNECTIONS( scp ) && SVC_FORKS( sp ) && svc_looping( sp ) )
  601.         return( FAILED ) ;
  602.  
  603.     if ( svc_access_control( sp, cp ) == OK )
  604.         return( server_run( sp, cp ) ) ;
  605.  
  606.     if ( M_IS_SET( scp->log_on_failure, LO_USERID ) &&
  607.                                                     ACCEPTS_CONNECTIONS( scp ) )
  608.         (void) conn_add_alternative( cp, LOG_SERVICE( ps ) ) ;
  609.  
  610.     if ( SDATA( sp )->shutdown != NULL )
  611.     {
  612.         if ( ! M_IS_SET( scp->log_on_failure, LO_RECORD ) || 
  613.                     conn_add_alternative( cp,
  614.                                 SHUTDOWN_SERVICE( ps ) ) == FAILED )
  615.             conn_shutdown( cp ) ;
  616.     }
  617.  
  618.     return( FAILED ) ;
  619. }
  620.  
  621.  
  622. status_e svc_access_control( sp, cp )
  623.     struct service *sp ;
  624.     connection_s *cp ;
  625. {
  626.     access_e result ;
  627.     access_e access_control() ;
  628.     void log_failure() ;
  629.  
  630.     result = access_control( sp, cp, MASK_NULL ) ;
  631.     if ( result != AC_OK )
  632.     {
  633.         log_failure( result, sp, cp ) ;
  634.         return( FAILED ) ;
  635.     }
  636.     return( OK ) ;
  637. }
  638.  
  639.  
  640. /*
  641.  * Implement shutdown protocol (usually sends an error indication).
  642.  */
  643. void svc_shutdown( sp, cp )
  644.     struct service *sp ;
  645.     connection_s *cp ;
  646. {
  647.     register struct service_config *scp = CONF( sp ) ;
  648.     int old_flags ;
  649.     int fd = cp->descriptor ;
  650.     bool_int change_flags = ! ACCEPTS_CONNECTIONS( scp ) ;
  651.     char *func = "svc_shutdown" ;
  652.  
  653.     if ( SDATA( sp )->shutdown == NULL )
  654.         return ;
  655.  
  656.     /*
  657.      * Ensure that we won't block in the shutdown function
  658.      */
  659.     if ( change_flags && ( old_flags = fcntl( fd, F_GETFL, 0 ) ) == -1 )
  660.     {
  661.         msg( LOG_ERR, func, "fcntl-getflags failed: %m" ) ;
  662.         return ;
  663.     }
  664.  
  665.    if ( fcntl( fd, F_SETFL, FNDELAY ) == -1 )
  666.       msg( LOG_ERR, func, "fcntl-setflags failed: %m" ) ;
  667.    else
  668.       (*SDATA( sp )->shutdown)( fd, (char **)0 ) ;
  669.  
  670.     if ( change_flags )
  671.         (void) fcntl( fd, F_SETFL, old_flags ) ;
  672. }
  673.  
  674.